#include "bsp_motor_stm32f103.h"
#include "bsp_common_stm32f103.h"

void Bsp_MotorInit_(void)
{

}

void Bsp_MotorDone_(void)
{
    Bsp_MotorClose_();
}

void Bsp_MotorOpen_(void)
{
    Drv_MotorOpen();
}

void Bsp_MotorClose_(void)
{
    Drv_MotorClose();
}

static void Bsp_MotorInitItemMember_(Bsp_TMotorItem* item)
{
    item->freq = 10000;     ///< 10KHz
    item->duty = 0;         ///< 0%
    item->direction = True;   ///< 前进

    item->is_open = False;
}

Bsp_THandle Bsp_MotorCreate(Int32 id)
{
    Bsp_THandle result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Int8 index;
    BSP_GET_INDEX(index, id);

    if (index >= 0)
    {
        Bsp_TMotorItem* item = &self->items[index];
        Bsp_MotorInitItemMember_(item);

        result = (Bsp_THandle)item;
    }
    else
        result = NULL;
    
    return result;
}

void Bsp_MotorFree(Bsp_THandle handle)
{
    Bsp_MotorClose(handle);
}

Int32 Bsp_MotorGetId(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;

        result = item->id;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_MotorOpen(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (!item->is_open)
        {
            Drv_MotorSetDirection(item);
            Drv_MotorSetDuty(item);
            item->is_open = True;

            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeOpened;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;    
}

Int32 Bsp_MotorClose(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            Bsp_MotorStop(handle);

            item->is_open = False;

            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;    
}

Bool Bsp_MotorIsOpen(Bsp_THandle handle)
{
    Bool result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;

        result = item->is_open;
    }
    else
        result = False;

    return result;
}

Int32 Bsp_MotorSetDirection(Bsp_THandle handle, Bool direction)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            item->direction = direction;
            Drv_MotorSetDirection(item);

            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_MotorGetDirection(Bsp_THandle handle, Bool* direction)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            *direction = item->direction;
            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_MotorSetSpeed(Bsp_THandle handle, Int32 speed)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            /// 得科驱动板要求占空比不高于96%，这里做限制，选择95%
            if (speed >= 95)
                speed = 95;
            item->duty = speed;
            Drv_MotorSetDuty(item);

            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_MotorGetSpeed(Bsp_THandle handle, Int32* speed)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            *speed = item->duty;
            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_MotorSetFreqDuty(Bsp_THandle handle, Int32 freq, Int32 duty)
{
    return Bsp_kErrorCodeNotSupport;
}

Int32 Bsp_MotorStart(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            Drv_MotorStart(item);
            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_MotorStop(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TMotorUnion* self = &g_bsp_motor_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TMotorItem* item = (Bsp_TMotorItem*)handle;
        
        if (item->is_open)
        {
            Drv_MotorStop(item);
            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}
